import { AsArray } from '../../interface';
import { clearAll } from '../object/object';

/**
 * 事件
 *
 * @author chitanda
 * @date 2022-08-30 17:08:14
 * @export
 * @class QXEventEmitter
 */
export class QXEventEmitter {
  /**
   * 事件组
   *
   * @private
   * @type {Map<string, any[]>}
   * @memberof QXEventEmitter
   */
  private map: Map<string, any[]> = new Map();

  /**
   * 最大事件监听数量
   *
   * @private
   * @type {number}
   * @memberof QXEventEmitter
   */
  private maxListeners = 100;

  /**
   * 设置单个事件最大监听数量
   *
   * @param {number} num
   * @memberof QXEventEmitter
   */
  setMaxListeners(num: number): void {
    this.maxListeners = num;
  }

  /**
   * 获取指定事件当前监听个数
   *
   * @author chitanda
   * @date 2022-10-26 19:10:54
   * @param {string} name
   * @return {*}  {number}
   */
  getSize(name: string): number {
    if (this.map.has(name)) {
      const events = this.map.get(name)!;
      return events.length;
    }
    return 0;
  }

  /**
   * 订阅事件
   *
   * @author chitanda
   * @date 2022-08-21 18:08:36
   * @param {string} name
   * @param {(...args: AsArray<any>) => unknown} fn
   */
  addListener(name: string, fn: (...args: AsArray<any>) => unknown): void {
    if (fn instanceof Function) {
      if (!this.map.has(name)) {
        this.map.set(name, []);
      }
      const events = this.map.get(name)!;
      if (events.length < this.maxListeners) {
        events.push(fn);
      } else {
        throw new Error(
          `事件监听已达最大上限[${this.maxListeners}]，无法新增监听!`,
        );
      }
    }
  }

  /**
   * 取消订阅
   *
   * @author chitanda
   * @date 2022-08-21 18:08:30
   * @param {string} name
   * @param {(...args: AsArray<any>) => unknown} fn
   */
  removeListener(name: string, fn: (...args: AsArray<any>) => unknown): void {
    if (this.map.has(name)) {
      const events = this.map.get(name)!;
      if (events.length > 0) {
        for (let i = 0; i < events.length; i++) {
          const item = events[i];
          if (item === fn) {
            events.splice(i, 1);
            break;
          }
        }
      }
    }
  }

  /**
   * 发送事件
   *
   * @author chitanda
   * @date 2022-08-21 18:08:00
   * @param {string} name
   * @param {...AsArray<any>} args
   */
  emit(name: string, ...args: AsArray<any>): void {
    if (this.map.has(name)) {
      const events = this.map.get(name)!;
      events.forEach((fn: (..._args: AsArray<any>) => void) => {
        fn(...args);
      });
    }
  }

  /**
   * 等待所有事件执行完毕
   *
   * @author chitanda
   * @date 2022-08-21 18:08:44
   * @template R
   * @param {string} name
   * @param {...AsArray<any>} args
   * @return {*}  {Promise<R[]>}
   */
  async asyncEmit<R = void>(name: string, ...args: AsArray<any>): Promise<R[]> {
    if (this.map.has(name)) {
      const events = this.map.get(name)!;
      const all = events.map((fn: (..._args: AsArray<any>) => Promise<R>) =>
        fn(...args),
      );
      return Promise.all(all);
    }
    return [];
  }

  /**
   * 释放所有事件监听
   *
   * @author chitanda
   * @date 2022-08-30 17:08:04
   */
  reset(): void {
    this.map.forEach(val => {
      clearAll(val);
    });
    this.map.clear();
  }
}
